/*
 * Created on 03.12.2003
 */
package de.javakicker;

import java.io.*;
import java.util.*;
import java.awt.Point;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

/**
 * The Class XmlActionSource.
 *
 * @author Till Krullmann
 */
public class XmlActionSource extends DefaultHandler implements ActionSource
{	
	
	/**
	 * Parses the point.
	 *
	 * @param attr the attr
	 * @return the point
	 */
	private static Point parsePoint(Attributes attr)
	{
		return new Point( Integer.parseInt(attr.getValue("x")),
						  Integer.parseInt(attr.getValue("y")));
	}
	
	
	/**
	 * The Class XmlAction.
	 */
	private class XmlAction implements ActionSource.Action
	{
		
		/** The actor id. */
		private String actorId;
		
		/** The soccer action. */
		private SoccerAction soccerAction;
		
		/**
		 * Instantiates a new xml action.
		 *
		 * @param attr the attr
		 */
		public XmlAction(Attributes attr)
		{
			actorId = attr.getValue("name");
			
			Point oldPos = (Point) positions.get(actorId);
			Point target = parsePoint(attr);
			
			int direction = Player.NOTHING;
			if (target.x < oldPos.x)
				direction = Player.LEFT;
			else if (target.x > oldPos.x)
				direction = Player.RIGHT;
			else if (target.y < oldPos.y)
				direction = Player.UP;
			else if (target.y > oldPos.y)
				direction = Player.DOWN;
				
			positions.put(actorId, target);

			soccerAction = new SoccerAction(attr.getValue("type"), direction);
		}
		
		/**
		 * Gets Actor Id
		 *
		 * @return the Actor Id
		 */
		public String getActorId()
		{
			return actorId;
		}
		
		/**
		 * Gets the SoccerAction
		 *
		 * @return the SoccerAction
		 */
		public SoccerAction getSoccerAction()
		{
			return soccerAction;	
		}
	}
	
	
	/**
	 * The Class XmlReset.
	 */
	public class XmlReset implements ActionSource.Reset
	{
		
		/**
		 * The Class XmlResetEntry.
		 */
		public class XmlResetEntry
		{
			
			/**
			 * Instantiates a new xml reset entry.
			 *
			 * @param teamId the team id
			 * @param position the position
			 */
			public XmlResetEntry(int teamId, Point position)
			{
				this.teamId = teamId;
				this.position = position;
			}
			
			/** The team id. */
			public int teamId;
			
			/** The position. */
			public Point position;
		}
		
		
		/** The entries. */
		Map<String, XmlResetEntry> entries = new Hashtable<String, XmlResetEntry>();
				
		
		/**
		 * Instantiates a new xml reset.
		 */
		public XmlReset()
		{
			positions.clear();
		}
		
		
		/**
		 * Adds the entry.
		 *
		 * @param attr the attr
		 */
		public void addEntry(Attributes attr)
		{
			XmlResetEntry entry = new XmlResetEntry(
				Integer.parseInt(attr.getValue("team")) - 1,
				parsePoint(attr));
			
			entries.put(attr.getValue("name"), entry);
			
			positions.put(attr.getValue("name"), entry.position);
		}
		
		
		/**
		 * Gets Actor Ids as String Array
		 *
		 * @return the Actor Ids as String Array
		 */
		public String[] getActorIds()
		{
			return (String[]) entries.keySet().toArray();
		}
		
		
		/**
		 * Gets the Actor Position
		 *
		 * @return  the Actor Position
		 */
		public Point getPosition(String actorId)
		{
			return ((XmlResetEntry) entries.get(actorId)).position;
		}
		
		
		/**
		 * Gets the Actor TeamIndex
		 *
		 * @return  the Actor TeamIndex
		 */
		public int getTeamIndex(String actorId)
		{
			return ((XmlResetEntry) entries.get(actorId)).teamId;
		}
	}
	
	
	/** The team names. */
	private String[] teamNames = new String[2];
	
	/** The positions. */
	private Map<String, Point> positions = new Hashtable<String, Point>();
	
	/** The actions. */
	private LinkedList<Object> actions = new LinkedList<Object>();
	
	/** The open reset. */
	XmlReset openReset = null;
	
	
	/**
	 * Instantiates a new xml action source.
	 *
	 * @param file the file
	 * @throws SAXException the sAX exception
	 * @throws FileNotFoundException the file not found exception
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public XmlActionSource(File file)
		throws SAXException, FileNotFoundException, IOException
	{
		this(new InputSource(new FileReader(file)));
	}
	
	
	/**
	 * Instantiates a new xml action source.
	 *
	 * @param source the source
	 * @throws SAXException the sAX exception
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public XmlActionSource(InputSource source)
		throws SAXException, IOException
	{
		XMLReader reader = XMLReaderFactory.createXMLReader();
		reader.setContentHandler(this);
		reader.parse(source);
	}
	
	
	/* 
	 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
	 */
	public void startElement(String uri, String localName,
					  String qName, Attributes attr)
	{
		if (localName.equals("minute"))
		{
			actions.addLast(NEXT_MINUTE);
		}
		else if (localName.equals("action"))
		{
			actions.addLast(new XmlAction(attr));
		}
		else if (localName.equals("init"))
		{
			openReset.addEntry(attr);
		}
		else if (localName.equals("reset"))
		{
			openReset = new XmlReset();
		}
		else if (localName.equals("team"))
		{
			teamNames[ Integer.parseInt(attr.getValue("id")) - 1 ] =
				attr.getValue("name");
		}
	}
	
	
	/* 
	 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
	 */
	public void endElement (String uri, String localName, String qName)
	{
		if (localName.equals("reset"))
		{
			actions.addLast(openReset);
			openReset = null;
		}
	}
	
	
	/* 
	 * @see javakicker.de.ActionSource#getTeamNames()
	 */
	public String[] getTeamNames()
	{
		return teamNames;
	}
	


	/** 
	 *Die naechste Aktion ist entweder eine SoccerAction oder ein Reset
	 */
	public Object nextAction()
	{
		if (actions.isEmpty())
			return null;
		else
			return actions.removeFirst();
	}
	
	
	/* 
	 * @see javakicker.de.ActionSource#peekAction()
	 */
	public Object peekAction()
	{
		if (actions.isEmpty())
			return null;
		else
			return actions.getFirst();
	}

}
